/*!
 * Copyright (c) 2007-2009, stauren.net. All rights reserved.
 * javascript and css loader of double-underscore,
 * visit : http://code.google.com/p/double-underscore/
 * @file loader.js
 * @revision:
 * @author <a href="mailto:stauren@stauren.net">stauren</a>
 */

(function(_scope) {

var DU_TAG = '0.3.2',
_NAME = '__';

_scope[_NAME] = _scope[_NAME] || {};

var _SELF = _scope[_NAME];

if (!_SELF.add) {

  _SELF.cfg = _SELF.cfg || [];
  _SELF.config = _SELF.config || {};

  var _WINDOW = _scope,
  _DOCUMENT = _scope.document,
  _CREATEELEMENT = 'createElement',
  _SCRIPT = 'script',
  _ONSUCCESS = 'onSuccess',
  _TYPE = 'type',
  _LENGTH = 'length',
  _SPLIT = 'split',
  _JOIN = 'join',
  _TEST = 'test',
  _MATCH = 'match',
  _PROTOTYPE = 'prototype',
  _INDEXOF = 'indexOf',
  _LASTINDEXOF = 'lastIndexOf',
  _ONREADYSTATECHANGE = 'onreadystatechange',
  _PARENTNODE = 'parentNode',
  _APPENDCHILD = 'appendChild',
  _REMOVECHILD = 'removeChild',
  _TRUE = true,
  _FALSE = false,
  _UNDEFINED,
  _BRANCHES = { //code branches
    'woodsprite': 0,
  },
  _SC = _SELF.config,
  _CFG = _SELF.cfg,
  ua = navigator.userAgent,
  cua,
  loadingList = {},
  _configNames,
  _defCfg = [
    {}, //0, appCfg
    _FALSE, //1, debug
    DU_TAG, //2, duTag
    'http://double-underscore.googlecode.com/svn', //3, loaderBase
    {}, //4, ua
    {}, //5, loaderModules
    !(_scope.console && _scope.console.log), //6, logByDiv
    'du-logger-container', //7, loggerContainerId 
    //set to true for the access of data in _.log.data
    _FALSE, //8, recordingLog,
    'http://double-underscore.appspot.com/', //9, reporting img host
    _FALSE//10, do report
  ],
  /**
   * attach a module to the global namespace if not exists
   * could be accessed though __[n]
   * @param {string} n name of the module
   * @param {object} o the module
   */
  _add = function(n, o) {
    _SELF[n] = n in _SELF ? _SELF[n] : o;
  };

  _configNames = 'appCfg debug duTag loaderBase ua loaderModules logByDiv loggerContainerId recordingLog'[_SPLIT](' ');
  _SC.configName = _configNames;
  _SC.win = _WINDOW;
  _SC.doc = _DOCUMENT;

  //init config, .config will overwrite .cfg, but cfg is used in runtime
  for (var i=0,j=_defCfg[_LENGTH];i<j;++i) {
    _CFG[i] = _configNames[i] in _SC ? _SC[_configNames[i]] : (_CFG[i] === _UNDEFINED ?
      _defCfg[i] : _CFG[i]);
  }
  _SC.ua = _CFG[4];

  //log
  if (!_CFG[1] && _CFG[10]) {
    (new Image()).src = [_CFG[9], '?duv=', DU_TAG, '&hu=', encodeURIComponent(location.href)][_JOIN]('');
  }

  cua = _CFG[4];
  if ((/KHTML/)[_TEST](ua)) {
    cua.webkit = _TRUE;
  } else if (/Opera/[_TEST](ua)) {
    cua.opera= ua[_MATCH](/Opera\/([0-9.]+)/)[1];
  } else if (/MSIE \d/[_TEST](ua)) {
    cua.ie = ua[_MATCH](/MSIE (\d)/)[1];
  } else if (/Gecko/[_TEST](ua)) {
    cua.gecko = _TRUE;
  }

  var _loadFile = function(type, url, obj) {
    obj = obj || {};
    var head = _DOCUMENT.getElementsByTagName("head")[0] || _DOCUMENT.documentElement,
      node, usera = _CFG[4],
      fn = typeof obj[_ONSUCCESS] == 'function' ? obj[_ONSUCCESS] : function(){};

    if(type == _SCRIPT){
      node = _DOCUMENT[_CREATEELEMENT](_SCRIPT);
      node[_TYPE] = 'text/javascript';
      node.src = url;
    } else if(type =="css") {
      node = _DOCUMENT[_CREATEELEMENT]('link');
      node[_TYPE] = 'text/css';
      node.rel = 'stylesheet';
      node.href = url;
    }

    if (node.charset) {
      node.charset = obj.charset;
    }
    if (usera.ie) {
      node[_ONREADYSTATECHANGE] = function() {
        var rs = this.readyState;
        if ("loaded" === rs || "complete" === rs) {
          fn();
          this[_ONREADYSTATECHANGE] = null;
          if (type == _SCRIPT) {
            node[_PARENTNODE][_REMOVECHILD](node);
          }
          node = null;
        }
      };
    } else if (usera.webkit) {
      if (type == _SCRIPT) {
        node.addEventListener("load", function() {
          fn();
          node[_PARENTNODE][_REMOVECHILD](node);
          node = null;
        });
      }
    } else {
      node.onload = function() {
        fn();
        if (!_CFG[4].opera || type == _SCRIPT) {
          node[_PARENTNODE][_REMOVECHILD](node);
        }
        node = null;
      };
    }
    head[_APPENDCHILD](node);
  }, _loadModuleByName = function(modName,getObj) {
    var loadingItem = loadingList[":"+modName],
      type = loadingItem && loadingItem.detailObj[_TYPE],
      fp, cache = getObj && getObj.cache;
   /* if (getObj && getObj.dynamic) {
      inHead = !!getObj.dynamic;
    }*/

    fp = loadingItem ? loadingItem.get(getObj) : modName; 
    if (!type) {
      type = fp.substr(fp[_LENGTH]-3).toLowerCase() == 'css' ?
        'css' : _SCRIPT;
    }
    if (cache === _FALSE || (_CFG[1] && cache !== _TRUE)) {
      fp += (fp[_INDEXOF]('?') > 0 ? '&' : '?') +'_du_r_t='+Math.random();
    }
    _loadFile(type, fp, getObj);
  },
  /**
   * usage : __.load('xxx', callback, obj), __.load('xxx yyy', obj), __.load(['xx', 'yy'], callback),
   * callback and obj could both be ignored
   * @param {string|array} n an url of js file or module names to load,
   *                       array of module names will be load simultaneously,
   *                       space seperated string of module names will be load in tandem
   * @param {function} onSuccess the onload call back,
   *                   this parameter equals getObj.onSuccess, could be omitted
   * @param {object} getObj configuration
   * @config {function} onSuccess the onload call back
   * @config {string} version version, 0 mean trunk
   * @config {string} type css or js
   * @config {boolean} cache add a random get param to the url
   * @config {string} charset default utf-8
   */
  _load = function(n,getObj) {
    var newObj, firstN;
    if (typeof getObj == 'function') {
      newObj = arguments[2] || {};
      newObj[_ONSUCCESS] = getObj;
      getObj = newObj;
    }
    if (Object[_PROTOTYPE].toString.apply(n) === '[object Array]') {
      for (var i=0,j=n[_LENGTH];i<j;++i) {
        _load(n[i], getObj);
      }
    } else {
      n = n[_SPLIT](' ');
      firstN = n.shift();
      if (n[_LENGTH] >= 1)  {
        newObj = {};
        for (var at in getObj) {
          if (getObj.hasOwnProperty(at)) {
            newObj[at] = getObj[at];
          }
        }
        newObj[_ONSUCCESS] = function() { _load(n[_JOIN](' '), getObj); };
      } else {
        newObj = getObj;
      }

      _loadModuleByName(firstN, newObj);
    }
  },

  /**
   * add a module infor to the loading list of loader
   *                   this parameter equals getObj.onSuccess, could be omitted
   * @param {string} n name of the module
   * @param {object} detailObj module detail infor about how to load it
   * @config {string} fileName file name of the module, default is n
   * @config {string} fullPath loader will load this module by fullPath without calculation
   * @config {string} afterBasePath loader will load this module through
   *                  basePath + '\' + afterBasePath
   * @config {string} type default is 'js', could be 'css'
   */
  _addModule = function(n, detailObj) {
    loadingList[":"+ n] = new _LoadModule(n, detailObj);
  },

  _LoadModule = function (modName, detailObj) {
    this.mname = modName;
    detailObj = detailObj || {};
    if (modName[_LENGTH] - modName[_LASTINDEXOF]('_css') == 4) {//end with _css
      detailObj.fileName = 'fileName' in detailObj ? detailObj.fileName :
        modName.substring(0, modName[_LASTINDEXOF]('_css'));
      detailObj[_TYPE] = 'css';
    }
    this.detailObj = detailObj;
  };

  _LoadModule[_PROTOTYPE].get = function(getObj) {
    getObj = getObj || {};
    var detObj = this.detailObj;

    if (detObj.fullPath) {
      return detObj.fullPath;
    }

    if (detObj.afterBasePath) {
      return [_CFG[3], detObj.afterBasePath][_JOIN]('/');
    }

    var type = detObj[_TYPE] || 'js',
      //source = this.detailObj['source'] || 'DU',
      sBase, name = detObj.fileName || this.mname;

    sBase = _CFG[3];
    var edition = _CFG[1] ? ((getObj.version && (getObj.version in _BRANCHES)) ?
       getObj.version : '0') : (getObj.version || _CFG[2]);
    if (edition == '0') { // load trunk
      sBase += '/trunk/src';
    } else if (edition in _BRANCHES) { // load branches
      sBase += '/branches/' + edition + '/src';
    } else { // load special tags
      sBase += '/tags/' + edition + '/pkgs';
    }

    name += type == 'css' ? '.css' : '.js';

    return [sBase, this.mname, name][_JOIN]('/');
  };

  _addModule('core');
  _addModule('json');
  _addModule('tool');
  _addModule('log');
  _addModule('anim');
  _addModule('flash');

  _addModule('du');

  _addModule('select');

  _addModule('popup');
  _addModule('calendar');
  _addModule('calendar_css');
  _addModule('validator');
  _addModule('validator_css');

  _addModule('imguploader');
  _addModule('imgcropper');
  _addModule('imguploader_css');
  _addModule('imgcropper');

  _addModule('cdselector');
  _addModule('cdselector_css');
  _addModule('cds_data_region');

  //_addModule('jslitmus', { afterBasePath : 'trunk/lib/JSLitmus.js' });

  _add('load', _load);
  _add('addModule', _addModule);
  _add('add', _add);
}
})(this);
